/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 * */

// AmzServer - Tototoy's server model.
// Author: tonyjobmails@gmail.com (tonyhack).
//
// Define class TimeTick.
// TimeTick gives some method to get serval kinds of time. This is not thread-save.
//

#ifndef __TIME__TICK__H
#define __TIME__TICK__H

#include <time.h>

#include "common.h"

namespace amz {

class TimeTick {
 public:
  TimeTick() {}
  ~TimeTick() {}

  TimeTick(const TimeTick &time_tick) {
    this->real_time_ = time_tick.real_time_;
    this->progress_time_ = time_tick.progress_time_;
    this->thread_time_ = time_tick.thread_time_;
    this->system_time_ = time_tick.system_time_;
  }

  // Updata all times.
  void Update() {
    clock_gettime(CLOCK_REALTIME, &this->real_time_);
    clock_gettime(CLOCK_MONOTONIC, &this->system_time_);
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &this->progress_time_);
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &this->progress_time_);
  }

  // Nano seconds From 1970-1-1 0:0:0 to now.
  inline timespec GetRealTime() const {
    return this->real_time_;
  }
  // Seconds
  inline time_t GetRealSec() const {
    return this->real_time_.tv_sec;
  }
  // Small Seconds.
  inline uint32 GetSmallRealSec() const {
    return (uint32)this->real_time_.tv_sec;
  }

  // Progress count(progress cpu count).
  inline timespec GetProgressTime() const {
    return this->progress_time_;
  }
  inline time_t GetProgressSec() const {
    return this->progress_time_.tv_sec;
  }
  inline uint32 GetSmallProgressSec() const {
    return (uint32)this->progress_time_.tv_sec;
  }

  // Thread count(thread cpu count).
  inline timespec GetThreadTime() const {
    return this->thread_time_;
  }
  inline time_t GetThreadSec() const {
    return this->thread_time_.tv_sec;
  }
  inline uint32 GetSmallThreadSec() const {
    return (uint32)this->thread_time_.tv_sec;
  }

  // System count(from start system to now).
  inline timespec GetSystemTime() const {
    return this->system_time_;
  }
  inline time_t GetSystemSec() const {
    return this->system_time_.tv_sec;
  }
  inline uint32 GetSmallSystemSec() const {
    return (uint32)this->system_time_.tv_sec;
  }
  inline uint32 GetSmallSystemMsec() const {
    return (uint32)(this->system_time_.tv_sec * 1000 + this->system_time_.tv_nsec / 1000);
  }

 private:
  // Nanoseconds From 1970-1-1 0:0:0 to now.
  timespec real_time_;
  // Progress count.
  timespec progress_time_;
  // Thread count.
  timespec thread_time_;
  // System count.
  timespec system_time_;
};


// This is a max-length 49 days timestamp.
class TimestampMillisecond {
 public:
  TimestampMillisecond() : timestamp_(0){}
  explicit TimestampMillisecond(const TimeTick &time_tick) {
    this->Stamp(time_tick);
  }
  ~TimestampMillisecond() {}

  inline void Stamp() {
    timespec time;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time);
    // millisecond.
    this->timestamp_ = time.tv_sec * 1000 + time.tv_nsec / 1000;
  }
  inline void Stamp(const TimeTick &time_tick) {
    this->timestamp_ = time_tick.GetSmallSystemMsec();
  }

  inline uint32 GetStamp() const {
    return this->timestamp_;
  }

  // Attendion, the parameter must be the later one.
  // This distance will get a wrong value if any timestamp return to zero twice.
  uint32 Distance(const TimestampMillisecond &bigger) const {
    // overflow.
    if(bigger.GetStamp() < this->timestamp_) {
      return kuint32max - (this->timestamp_ - bigger.GetStamp());
    }
    return bigger.GetStamp() - this->timestamp_;
  }

  const TimestampMillisecond operator = (const TimestampMillisecond &timestamp) {
    this->timestamp_ = timestamp.timestamp_;
    return *this;
  }

 private:
  // milisecond.
  uint32 timestamp_;
};

}  // namespace amz

#endif  // __TIME__TICK__H

